/*******************************************************************************
  CAN Driver Functions for Static Single Instance Driver

  Company:
    Microchip Technology Inc.

  File Name:
    drv_can_static.c

  Summary:
    CAN driver implementation for the static single instance driver.

  Description:
    The CAN device driver provides a simple interface to manage the CAN
    modules on Microchip microcontrollers.
    
  Remarks:
    Static interfaces incorporate the driver instance number within the names
    of the routines, eliminating the need for an object ID or object handle.
    Static single-open interfaces also eliminate the need for the open handle.
*******************************************************************************/

//DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2014 released Microchip Technology Inc.  All rights reserved.

Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).

You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.

SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTOCULAR PURPOSE.
IN NO EVENT SHALL MOCROCHIP OR ITS LOCENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STROCT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVOCES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*******************************************************************************/
//DOM-IGNORE-END

// *****************************************************************************
// *****************************************************************************
// Header Includes
// *****************************************************************************
// *****************************************************************************
#include "system_config.h"
#include "system_definitions.h"
#include "os.h"
#include "../drv_can_static.h"

#include "user_config.h"

static CAN_TX_MSG_BUFFER  *drv_Message0;
static CAN_TX_MSG_BUFFER  can_message_buffer0[2*2*16];


OS_SEM   can0_lock_sem;

OS_SEM   can0_recv_sem;

extern OS_SEM   freq_ctrl_sem; //远程控制AO输出信号量。 

// *****************************************************************************
// *****************************************************************************
// Section: Instance 0 static driver functions
// *****************************************************************************
// *****************************************************************************
void DRV_CAN0_Initialize(void)
{
    uint32_t baud_rate = 0;

    switch(cfg_tbl[CFG_OFS_CAN_BAUD_RATE]){
	    case 0:	
		    baud_rate = 125;
		    break;
	    case 1:	
		    baud_rate = 250;
		    break;
	    case 2:	
		    baud_rate = 500;
		    break;
	    case 4:	
		    baud_rate = 1000;
		    break;
	    default:	
		    baud_rate = 125;
		    break;
    }				/* -----  end switch  ----- */
    /* Switch the CAN module ON */
    PLIB_CAN_Enable(CAN_ID_1);
    
    /* Switch the CAN module to Configuration mode. Wait until the switch is complete */
    PLIB_CAN_OperationModeSelect(CAN_ID_1, CAN_CONFIGURATION_MODE);
    while(PLIB_CAN_OperationModeGet(CAN_ID_1) != CAN_CONFIGURATION_MODE);

    PLIB_CAN_PhaseSegment2LengthFreelyProgrammableEnable(CAN_ID_1);

    //Set the Baud rate to 1000 kbps
//    PLIB_CAN_PropagationTimeSegmentSet(CAN_ID_1, 1-1);
//    PLIB_CAN_PhaseSegment1LengthSet(CAN_ID_1, 3-1);
//    PLIB_CAN_PhaseSegment2LengthSet(CAN_ID_1, 3 - 1);
//    PLIB_CAN_SyncJumpWidthSet(CAN_ID_1, 1 - 1);
//    PLIB_CAN_BaudRatePrescaleSet(CAN_ID_1, 4); // set to 1 higher then ECAN tool


//    步骤 1：计算 FTQ。
//如果 FBAUD = 1 Mbps，且时间份额数 N = 10，则 FTQ = 10 MHz。
//步骤2： 计算波特率预分频比（假设PIC32器件的运行频率为80 MHz，即FSYS = 80000000） 。
//CiCFG<BRP> = ( 80000000/(2 * FTQ) ) - 1 = 3。
//步骤 3：选择各个位时间段。
//同步段 = 1 TQ （常量）。
//基于系统特性，假设传播延时 = 3 TQ。 假设采样点位于标称位时间的 70% 位置处，那么：
//相位缓冲段 2 = 标称位时间的 30% = 3 TQ。
//相位缓冲段 1 = 10 TQ - (1 TQ + 3 TQ + 3 TQ) = 3 TQ。
    /* Fsys = System Clock Frequency = 40000000; */
    /* Fbaud = CAN bit rate = 1000000; */
    /* N = Time Quanta (Tq) per bit = 10; */
    /* Prop Segment = 3 Tq */
    /* Phase Seg 1 = 3 Tq */
    /* Phase Seg 2 = 3 Tq */
    /* Sync Jump Width = 2 Tq */
    /* Ensure the CAN module is in configuration mode.*/
//    C1CONbits.REQOP = 4
//    while(C1CONbits.OPMOD != 4);      //进入配置模式


    C1CFGbits.SEG2PHTS = 1; /* Phase seg 2 is freely programmable */
    C1CFGbits.SEG2PH = 2; /* Phase seg 2 is 3 Tq. */
    C1CFGbits.SEG1PH = 2; /* Phase seg 1 is 3 Tq. */
    C1CFGbits.PRSEG = 2; /* Propagation seg 2 is 3 Tq. */
    C1CFGbits.SAM = 1; /* Sample bit 3 times. */
    C1CFGbits.SJW = 2; /* Sync jump width is 2 Tq */
//    C1CFGbits.BRP = 3; /* BRP value as calculated in Example 34-11 */
    C1CFGbits.BRP = (SYS_CLK_FREQ/(2*(baud_rate * 10000))) -1;
    /* CAN bit rate configuration complete. */



    /* Assign the buffer area to the CAN module.
      In this case assign enough memory for 2
      channels, each with 8 message buffers.*/
    C1FIFOBA = KVA_TO_PA(can_message_buffer0); // work around for broken PLIB above

    //     C1FIFOCON0bits.FSIZE = 1;
//     C1FIFOCON0SET = 0X80;
//
//     C1FIFOCON1bits.FSIZE = 1;
//     C1FIFOCON1CLR = 0X80;
     /* Configure CAN_ID_1 Channel for CAN_TX_RTR_ENABLED operation. Allocate 1 message buffer, and assign low medium priority for transmissions. */
     PLIB_CAN_ChannelForTransmitSet(CAN_ID_1, CAN_CHANNEL0, 1, CAN_TX_RTR_ENABLED, CAN_LOW_MEDIUM_PRIORITY);
     /* Configure CAN_ID_1 Channel for CAN_RX_FULL_RECEIVE operation. Allocate 1 message buffer, and assign low medium priority for transmissions. */
     PLIB_CAN_ChannelForReceiveSet(CAN_ID_1, CAN_CHANNEL1, 1, CAN_RX_FULL_RECEIVE);

//     C1RXF0bits.SID = 0x100; /* Configure Filter 0. */
//     C1RXF0bits.EXID = 0;
//     C1RXM0bits.SID = 0x1FF; /* Configure Mask 0. */
//    C1RXM0bits.MIDE = 0;

    C1FLTCON0bits.FSEL0 = 1; /* Store messages in FIFO1 */
    C1FLTCON0bits.MSEL0 = 0; /* Use Mask 0 */
    C1RXF0bits.SID = 8; /* Filter 3 SID */
    C1RXF0bits.EXID = 0;

    C1RXM0bits.SID = 0x00; /* Ignore last 2 bits in comparison */
    C1RXM0bits.MIDE = 1; /* Match only message types. */

//    C1FLTCON0bits.FLTEN0 = 1; /* Enable the filter */

//     PLIB_CAN_FilterToChannelLink(CAN_ID_1, CAN_FILTER0, CAN_FILTER_MASK0, CAN_CHANNEL1);

     PLIB_CAN_ChannelEventEnable(CAN_ID_1, CAN_CHANNEL1, CAN_RX_CHANNEL_NOT_EMPTY);
     C1FLTCON0bits.FLTEN0 = 1;   //使能过滤器0




    /* Switch the CAN module to Normal mode. Wait until the switch is complete */
    PLIB_CAN_OperationModeSelect(CAN_ID_1, CAN_NORMAL_MODE);
    while(PLIB_CAN_OperationModeGet(CAN_ID_1) != CAN_NORMAL_MODE);

    PLIB_CAN_ModuleEventEnable(CAN_ID_1 , 0|CAN_RX_EVENT|CAN_RX_OVERFLOW_EVENT|CAN_SYSTEM_ERROR_EVENT|CAN_BUS_ERROR_EVENT);


    /* Setup CAN_ID_1 Interrupt */
    PLIB_INT_SourceEnable(INT_ID_0,INT_SOURCE_CAN_1);
    PLIB_INT_VectorPrioritySet(INT_ID_0,INT_VECTOR_CAN1, INT_PRIORITY_LEVEL1);
    PLIB_INT_VectorSubPrioritySet(INT_ID_0,INT_VECTOR_CAN1, INT_SUBPRIORITY_LEVEL0);


    OSAL_SEM_Create(&can0_recv_sem, 0, 0, 0);
    OSAL_SEM_Create(&can0_lock_sem, 0, 0, 1);

    OSAL_SEM_Create(&freq_ctrl_sem, 0, 0, 0);//远程控制AO输出信号量。
}

void DRV_CAN0_DeInitialize(void)
{

    /* Switch the CAN module to Disable mode. Wait until the switch is complete */
    PLIB_CAN_OperationModeSelect(CAN_ID_1, CAN_DISABLE_MODE);
    while(PLIB_CAN_OperationModeGet(CAN_ID_1) != CAN_DISABLE_MODE);	
    
}

void DRV_CAN0_Open(void)
{
   /* Switch the CAN module ON */
    PLIB_CAN_Enable(CAN_ID_1);
}

void DRV_CAN0_Close(void)
{
   /* Switch the CAN module OFF */
    PLIB_CAN_Disable(CAN_ID_1);
}

bool DRV_CAN0_ChannelMessageTransmit(CAN_CHANNEL channelNum, int address, uint8_t DLC, uint8_t* message)
{

    int i = 0;
    int count = 0;
    drv_Message0 = (CAN_TX_MSG_BUFFER *) &can_message_buffer0[channelNum];
    drv_Message0->msgSID.sid     = address;
    drv_Message0->msgEID.ide     = 0;
    drv_Message0->msgEID.data_length_code     = DLC;

    while(count < DLC)
    {
    	drv_Message0->data[count++] = *message++;
    }

    //Update CAN module and then transmit data on the bus;
    PLIB_CAN_ChannelUpdate(CAN_ID_1, channelNum);
    PLIB_CAN_TransmitChannelFlush(CAN_ID_1, channelNum);

    if(cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 2){
	    PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
	    printf("CAN Send:");
	    for (i = 0; i < DLC; i++)
		    printf("[%.2X]", drv_Message0->data[i]);
	    printf("\r\n");
	    PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
    }

    return(true);
   
}

bool DRV_CAN0_ChannelMessageReceive(CAN_CHANNEL channelNum, CAN_RX_MSG_BUFFER *RxMessage){

    int EchoDLC = 0;
    CAN_RX_MSG_BUFFER *RxMessage_temp;
    RxMessage_temp = (CAN_RX_MSG_BUFFER *) PLIB_CAN_ReceivedMessageGet(CAN_ID_1, channelNum);

    RxMessage->msgSID = RxMessage_temp->msgSID;
    RxMessage->msgEID.data_length_code = RxMessage_temp->msgEID.data_length_code;
    if (RxMessage_temp->msgEID.data_length_code > 0) {
        while (EchoDLC < RxMessage_temp->msgEID.data_length_code) {
            RxMessage->data[EchoDLC] = RxMessage_temp->data[EchoDLC];
            EchoDLC++;
        }
    }

    PLIB_CAN_ChannelUpdate(CAN_ID_1, channelNum);
}

/*******************************************************************************
 End of File
*/
